package com.yuandian.bpm.bi.modules.quartz.service.impl;

import cn.hutool.core.date.DateUtil;
import com.alibaba.csp.sentinel.util.StringUtil;
import com.yuandian.bpm.bi.modules.customs.sevice.CustomReportService;
import com.yuandian.bpm.bi.modules.email.service.EmailService;
import com.yuandian.bpm.bi.modules.quartz.enums.TaskStateEnum;
import com.yuandian.bpm.bi.modules.quartz.enums.TaskTypeEnum;
import com.yuandian.bpm.bi.modules.quartz.service.HandelBaseService;
import com.yuandian.bpm.bi.modules.quartz.util.CollectHardwareUtils;
import com.yuandian.bpm.bi.modules.quartz.util.CronUtil;
import com.yuandian.bpm.bi.modules.quartz.vo.ConfReportFileInfo;
import com.yuandian.bpm.bi.modules.quartz.vo.ConfReportTaskInfo;
import com.yuandian.bpm.bi.modules.quartz.vo.ConfReportTaskLog;
import com.yuandian.bpm.bi.modules.quartz.vo.ConfReportTaskVo;
import com.yuandian.bpm.common.core.util.R;
import lombok.extern.slf4j.Slf4j;
import org.quartz.JobExecutionContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.DayOfWeek;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;

/**
 * <p> 报表数据上报 实现层 </p>
 *
 * @Author: LinShiHe
 * @Date: 2022/9/19 16:20
 */
@Slf4j
@Service("reportPushHandelService")
public class HandelReportPushServiceImpl implements HandelBaseService {

	@Autowired
	CustomReportService customReportService;

	@Autowired
	EmailService emailService;

	@Override
	public ConfReportTaskVo handleData(ConfReportTaskInfo confReportTaskInfo, JobExecutionContext context) {
		ConfReportFileInfo fileInfo = new ConfReportFileInfo();		// 文件对象
		ConfReportTaskLog logInfo = new ConfReportTaskLog();		// 邮件对象
		ConfReportTaskVo resultVo = new ConfReportTaskVo();			// 结果集
		resultVo.setTaskType(TaskTypeEnum.REPORT.toString());		// 任务类型： 报表类
		boolean taskFlag = false; 								 // 本次任务调度执行结果
		int taskExecuteStatus = TaskStateEnum.RUNNING.getCode(); // 本次任务调度状态
		String logStr = "";										 // 本次任务调度日志
		String taskNotificationPolicy = confReportTaskInfo.getTaskNotificationPolicy();		// 任务通知方式  0:邮件 1:第三方接口
		List<String> taskNotificationPolicyList = new ArrayList<>();
		if (StringUtil.isNotEmpty(taskNotificationPolicy)) {
			taskNotificationPolicyList.addAll(Arrays.asList(taskNotificationPolicy.split(",")));
		}
		String reportFileName = confReportTaskInfo.getReportFileName();

		String taskPreviousTime = DateUtil.formatDateTime(context.getPreviousFireTime());		// 任务上次执行时间
		String taskNextTime = DateUtil.formatDateTime(context.getNextFireTime());				// 任务下次执行时间
		String taskExpectedTime = DateUtil.formatDateTime(context.getScheduledFireTime());		// 任务本次预定执行时间
		log.info("[任务执行]-[任务id: {}]-任务上次执行时间:{}, 任务下次执行时间: {}, 任务本次预定执行时间: {}",
				confReportTaskInfo.getId(),
				taskPreviousTime,
				taskNextTime,
				taskExpectedTime);



		try {

			// 计算本次调度的数据查询时间
			getQueryDataTimeAtmosphere(confReportTaskInfo);

			// 调用文件下载引擎
			long fileDownStartTime = System.currentTimeMillis();
			R<String> fileR = customReportService.fileDownHandle(confReportTaskInfo);
			long fileDownEndTime = System.currentTimeMillis();

			if (fileR != null && fileR.getCode() == 0) {

				// 更新文件信息
				fileInfo.setTaskId(confReportTaskInfo.getId());
				fileInfo.setTaskName(confReportTaskInfo.getTaskName());
				fileInfo.setReportTemplateId(confReportTaskInfo.getReportTemplateId());
				fileInfo.setReportTemplateName(confReportTaskInfo.getReportTemplateName());
				fileInfo.setReportFileName(fileR.getData());
				fileInfo.setReportFilePath(fileR.getData());
				fileInfo.setReportFileStatus(1);
				fileInfo.setReportQueryStartTime(confReportTaskInfo.getReportQueryStartTime());
				fileInfo.setReportQueryEndTime(confReportTaskInfo.getReportQueryEndTime());
				fileInfo.setReportFileRetentionTime(confReportTaskInfo.getReportFileRetentionTime());
				log.info("[任务执行]-[任务id: {}]-[文件下载]-[耗时: {} MS]-成功", confReportTaskInfo.getId(), (fileDownEndTime - fileDownStartTime));


				if (taskNotificationPolicyList.size() > 0) {
					// 进行邮件发送 或者第三方接口调用
					for (String policyType : taskNotificationPolicyList) {

						// 0:邮件 1:第三方接口
						if ("0".equals(policyType)) {
							log.info("[任务执行]-[任务id: {}]-进入'邮件发送'逻辑", confReportTaskInfo.getId());

							// 调用邮件发送引擎
							long sendEmailStartTime = System.currentTimeMillis();
							confReportTaskInfo.setReportFileName(fileR.getData());
							R<String> emailR = emailService.sendEmailHandle(confReportTaskInfo);

							if (emailR != null && emailR.getCode() == 0) {
								// 操作成功后，更新相关信息
								taskFlag = true;
								taskExecuteStatus = TaskStateEnum.RUNNING.getCode();
								logStr = String.format("[任务执行]-[任务id: %s]-[邮件发送]-[耗时: %s MS]-成功", confReportTaskInfo.getId(), (System.currentTimeMillis() - sendEmailStartTime));

								log.info(logStr);

							} else {
								taskFlag = false;
								taskExecuteStatus = TaskStateEnum.SUSPEND.getCode();
								logStr = String.format("[任务执行]-[任务id:  %s]-[邮件发送]-耗时:  %s MS-失败:  %s", confReportTaskInfo.getId(), fileDownEndTime - fileDownStartTime, fileR.getMsg());

								log.warn(logStr);
							}


						} else if ("1".equals(policyType)) {
							// 执行 webhook 调用
							log.info("[任务执行]-[任务id: {}]-进入Webhook调用逻辑", confReportTaskInfo.getId());
							long webhookStartTime = System.currentTimeMillis();

							// 操作成功后，更新相关信息
							taskFlag = true;
							taskExecuteStatus = TaskStateEnum.RUNNING.getCode();
							logStr = String.format("[任务执行]-[任务id: %s]-[Webhook]-[耗时: %s MS]-成功", confReportTaskInfo.getId(), (System.currentTimeMillis() - webhookStartTime));
							log.info(logStr);
						}

					}


				} else {
					// 进入此逻辑 表示无需'邮件发送'和'webhook调用'
					taskFlag = true;
					taskExecuteStatus = TaskStateEnum.RUNNING.getCode();
					logStr = String.format("[任务执行]-[任务id: %s]-[文件下载]-[耗时: %s MS]-成功, 无需'邮件发送'和'webhook调用'", confReportTaskInfo.getId(), (System.currentTimeMillis() - fileDownStartTime));
					log.info(logStr);
				}

			} else {
				// 文件下载失败
				taskFlag = false;
				taskExecuteStatus = TaskStateEnum.SUSPEND.getCode();
				logStr = String.format("[任务执行]-[任务id: %s]-[文件下载]-耗时: %s MS-失败: %s", confReportTaskInfo.getId(), fileDownEndTime - fileDownStartTime, (fileR == null ? null : fileR.getMsg()));

				log.warn(logStr);
			}

		} catch (Exception e) {
			taskFlag = false;
			taskExecuteStatus = TaskStateEnum.SUSPEND.getCode();
			logStr = String.format("[任务执行]-[任务id: %s]-异常: %s", confReportTaskInfo.getId(), e.getMessage());
			log.error(logStr);
			e.printStackTrace();
		}

		// 更新任务信息
		confReportTaskInfo.setTaskExecuteStatus(taskExecuteStatus);
		confReportTaskInfo.setTaskNextTime(StringUtil.isBlank(taskNextTime) ? null : taskNextTime);
		confReportTaskInfo.setTaskPreviousTime((StringUtil.isBlank(taskPreviousTime) ? null : taskPreviousTime));
		confReportTaskInfo.setTaskExecuteIp(CollectHardwareUtils.getInet4Address());
		confReportTaskInfo.setReportFileName(reportFileName);
		if (taskFlag) {
			// 任务成功后更新任务 已执行次数, 以及下次的数据查询时间
			int taskAlreadyExecuteCount = confReportTaskInfo.getTaskAlreadyExecuteCount() == null ? 0 : confReportTaskInfo.getTaskAlreadyExecuteCount();
			confReportTaskInfo.setTaskAlreadyExecuteCount(taskAlreadyExecuteCount + 1);
			updateNextQueryTime(confReportTaskInfo);
		}

		// 更新日志信息
		logInfo.setTaskId(confReportTaskInfo.getId());
		logInfo.setTaskName(confReportTaskInfo.getTaskName());
		logInfo.setTaskExecuteStatus(taskExecuteStatus);
		logInfo.setTaskExecuteIp(CollectHardwareUtils.getInet4Address());
		logInfo.setTaskExecuteTime(taskExpectedTime);
		logInfo.setTaskExecuteType("邮件类型");
		logInfo.setTaskExecuteMessage(logStr);
		logInfo.setReportQueryStartTime(confReportTaskInfo.getReportQueryStartTime());
		logInfo.setReportQueryEndTime(confReportTaskInfo.getReportQueryEndTime());
		logInfo.setReportTemplateId(confReportTaskInfo.getReportTemplateId());
		logInfo.setReportTemplateName(confReportTaskInfo.getReportTemplateName());

		// 设置结果集
		resultVo.setTaskFlag(taskFlag);
		resultVo.setConfReportFileInfo(fileInfo);
		resultVo.setConfReportTaskInfo(confReportTaskInfo);
		resultVo.setConfReportTaskLog(logInfo);

		return resultVo;
	}

	/**
	 * 更新下次查询时间
	 */
	private void updateNextQueryTime(ConfReportTaskInfo confReportTaskInfo) {
		if (1 == confReportTaskInfo.getTaskExecuteFrequency()) {
			// 选择 '简单重复执行' 的每次执行成功后都要更新查询时间供给下次查询
			String taskCronExpressionStr = confReportTaskInfo.getTaskCronExpressionStr();
			int value = Integer.parseInt(taskCronExpressionStr.split("_")[0]);
			String unit = taskCronExpressionStr.split("_")[1];
			String reportQueryStartTime; // 报表数据开始时间
			String reportQueryEndTime; // 报表数据结束时间
			switch (unit) {
				case "MIN":
					reportQueryStartTime = CronUtil.getAfterMinuteStr(confReportTaskInfo.getReportQueryStartTime(), value);
					reportQueryEndTime = CronUtil.getAfterMinuteStr(confReportTaskInfo.getReportQueryEndTime(), value);
					break;
				case "HOUR":
					reportQueryStartTime = CronUtil.getAfterHour(confReportTaskInfo.getReportQueryStartTime(), value);
					reportQueryEndTime = CronUtil.getAfterHour(confReportTaskInfo.getReportQueryEndTime(), value);
					break;
				case "DAY":
					reportQueryStartTime = CronUtil.getAfterDay(confReportTaskInfo.getReportQueryStartTime(), value);
					reportQueryEndTime = CronUtil.getAfterDay(confReportTaskInfo.getReportQueryEndTime(), value);
					break;
				case "WEEK":
					reportQueryStartTime = CronUtil.getAfterDay(confReportTaskInfo.getReportQueryStartTime(), value * 7);
					reportQueryEndTime = CronUtil.getAfterDay(confReportTaskInfo.getReportQueryEndTime(), value * 7);
					break;
				default:
					throw new IllegalStateException("Unexpected value: " + unit);
			}
			confReportTaskInfo.setReportQueryStartTime(reportQueryStartTime);
			confReportTaskInfo.setReportQueryEndTime(reportQueryEndTime);
		}
	}

	/**
	 * 计算查询时间
	 */
	private void getQueryDataTimeAtmosphere(ConfReportTaskInfo confReportTaskInfo) {

		String reportQueryStartTime; // 报表数据开始时间
		String reportQueryEndTime; // 报表数据结束时间

		if (2 == confReportTaskInfo.getTaskExecuteFrequency()) {
			// 选择cron表达式需要计算时间
			switch (confReportTaskInfo.getTaskCronExpression()) {
				case "0 30 18 ? * MON-FRI":
					reportQueryStartTime = DateUtil.format(new Date(), "yyyy-MM-dd 00:00:00"); // 当天 0 点
					reportQueryEndTime = DateUtil.format(new Date(), "yyyy-MM-dd 18:30:00");	 // 当天 18:30:00
				break;
				case "0 30 18 ? * 6L":
					reportQueryStartTime = DateUtil.beginOfMonth(new Date()).toString();			// 当月第一天 0 点
					reportQueryEndTime = DateUtil.format(new Date(), "yyyy-MM-dd 18:30:00"); // 当天 18:30:00
					break;
				case "0 30 18 L * ?":
					reportQueryStartTime = DateUtil.beginOfMonth(new Date()).toString();			// 当月第一天 0 点
					reportQueryEndTime = DateUtil.format(new Date(), "yyyy-MM-dd 18:30:00"); // 当天 18:30:00
					break;
				case "0 0 12 ? * SUN":
					// 获取当前日期
					LocalDate currentDate = LocalDate.now();
					// 获取当前日期所在的星期几
					DayOfWeek dayOfWeek = currentDate.getDayOfWeek();
					// 计算当前日期与周一之间的偏移量
					int daysToAdd = DayOfWeek.MONDAY.getValue() - dayOfWeek.getValue();
					// 获取当前周的周一日期
					LocalDate mondayDate = currentDate.plusDays(daysToAdd);
					reportQueryStartTime = DateUtil.parse(mondayDate.toString()).toString();
					reportQueryEndTime = DateUtil.format(new Date(), "yyyy-MM-dd 18:30:00"); // 当天 18:30:00
					break;

				default:
					throw new IllegalArgumentException("can not find date format for：" + confReportTaskInfo.getTaskCronExpression());
			}
			confReportTaskInfo.setReportQueryStartTime(reportQueryStartTime);
			confReportTaskInfo.setReportQueryEndTime(reportQueryEndTime);
		}
	}




	@Override
	public void monitorThead(ConfReportTaskInfo confReportTaskInfo) {}

	@Override
	public void insertData(ConfReportTaskInfo confReportTaskInfo) throws Exception {}
}
